package cn.lingyangwl.agile.pay.pay.process.qr;

import cn.lingyangwl.agile.pay.common.constants.Cs;
import cn.lingyangwl.agile.pay.common.service.PayOrderService;
import cn.lingyangwl.agile.pay.common.service.PaySysConfigService;
import cn.lingyangwl.agile.pay.common.utils.PayUtils;
import cn.lingyangwl.agile.pay.pay.channel.AbstractChannelUserService;
import cn.lingyangwl.agile.pay.pay.channel.IChannelUserService;
import cn.lingyangwl.agile.pay.pay.model.bo.MchAppConfigContext;
import cn.lingyangwl.agile.pay.pay.model.rqrs.cashier.CashierChannelUserRQ;
import cn.lingyangwl.agile.pay.pay.model.rqrs.cashier.CashierPayRQ;
import cn.lingyangwl.agile.pay.pay.model.rqrs.cashier.CashierRedirectRQ;
import cn.lingyangwl.agile.pay.pay.model.rqrs.payorder.payway.AliJsapiOrderExtRQ;
import cn.lingyangwl.agile.pay.pay.model.rqrs.payorder.payway.WxJsapiOrderExtRQ;
import cn.lingyangwl.agile.pay.pay.process.payorder.AbstractPayOrderProcess;
import cn.lingyangwl.agile.pay.pay.service.ConfigContextQueryService;
import cn.lingyangwl.agile.pay.pay.service.PayMchNotifyService;
import cn.lingyangwl.framework.core.response.Resp;
import cn.lingyangwl.framework.tool.core.exception.Assert;
import cn.lingyangwl.framework.tool.core.exception.BizException;
import cn.lingyangwl.agile.pay.constant.IfCodeEnum;
import cn.lingyangwl.agile.pay.model.bo.CashierTokenInfo;
import cn.lingyangwl.agile.pay.model.entity.PayOrder;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author shenguangyang
 */
@Service
public class QrCashierProcess extends AbstractPayOrderProcess {
    @Resource
    private PayOrderService payOrderService;
    @Resource
    private ConfigContextQueryService configContextQueryService;
    @Resource
    private PaySysConfigService sysConfigService;
    @Resource
    private PayMchNotifyService payMchNotifyService;

    /**
     * 返回 oauth2【获取uerId跳转地址】
     */
    public Resp<?> redirectUrl(CashierRedirectRQ req) {
        // 查询订单
        PayOrder payOrder = getPayOrder(req.getToken());

        CashierTokenInfo tokenInfo = CashierTokenInfo.builder()
                .payOrderNo(payOrder.getPayOrderNo()).appId(payOrder.getAppId()).mchNo(payOrder.getMchNo())
                .build();
        // 回调地址
        String redirectUrlEncode = sysConfigService.getDBApplicationConfig().genOauth2RedirectUrlEncode(tokenInfo);

        // 获取商户配置信息
        MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(payOrder.getMchNo(), payOrder.getAppId());

        // 获取接口并返回数据
        IChannelUserService channelUserService = getServiceByWayCode(req.getWayCode());
        Assert.notNull(mchAppConfigContext, new BizException("商户号和商户应用不匹配"));
        return Resp.ok(channelUserService.buildUserRedirectUrl(redirectUrlEncode, mchAppConfigContext));

    }

    /**
     * 获取userId
     */
    public Resp<?> channelUserId(CashierChannelUserRQ req) {
        // 查询订单
        PayOrder payOrder = getPayOrder(req.getToken());

        String wayCode = req.getWayCode();

        // 获取商户配置信息
        MchAppConfigContext mchAppConfigContext = configContextQueryService.queryMchInfoAndAppInfo(payOrder.getMchNo(), payOrder.getAppId());
        IChannelUserService channelUserService = getServiceByWayCode(wayCode);
        return Resp.ok(channelUserService.getChannelUserId((JSONObject) JSON.toJSON(req), mchAppConfigContext));

    }


    /**
     * 获取订单支付信息
     */
    public Resp<?> payOrderInfo(String token) throws Exception {
        // 查询订单
        PayOrder payOrder = getPayOrder(token);

        PayOrder resOrder = new PayOrder();
        resOrder.setClientIp(payOrder.getId());
        resOrder.setMchOrderNo(payOrder.getMchOrderNo());
        resOrder.setMchName(payOrder.getMchName());
        resOrder.setPayAmount(payOrder.getPayAmount());
        resOrder.setReturnUrl(payMchNotifyService.createReturnUrl(payOrder, configContextQueryService.queryMchInfoAndAppInfo(payOrder.getMchNo(), payOrder.getAppId()).getMchApp().getAccessKeyId()));
        return Resp.ok(resOrder);
    }


    /**
     * 调起下单接口, 返回支付数据包
     */
    public Resp<?> pay(CashierPayRQ req) throws Exception {
        String wayCode = req.getWayCode();

        Resp<?> apiRes = null;
        PayOrder payOrder = getPayOrder(req.getToken());
        if (wayCode.equals(Cs.PAY_WAY_CODE.ALI_JSAPI)) {
            apiRes = packageAlipayPayPackage(payOrder, req);
        } else if (wayCode.equals(Cs.PAY_WAY_CODE.WX_JSAPI)) {
            apiRes = packageWxpayPayPackage(payOrder, req);
        }

        return Resp.ok(apiRes);
    }


    /**
     * 获取支付宝的 支付参数
     */
    private Resp<?> packageAlipayPayPackage(PayOrder payOrder,  CashierPayRQ req)
            throws AlipayApiException {

        String channelUserId = req.getChannelUserId();
        AliJsapiOrderExtRQ rq = new AliJsapiOrderExtRQ();
        rq.setBuyerUserId(channelUserId);
        return this.unifiedOrder(req.getWayCode(), rq, payOrder);
    }


    /**
     * 获取微信的 支付参数
     */
    private Resp<?> packageWxpayPayPackage(PayOrder payOrder, CashierPayRQ req)
            throws AlipayApiException {

        String openId = req.getChannelUserId();
        WxJsapiOrderExtRQ rq = new WxJsapiOrderExtRQ();
        rq.setOpenid(openId);
        return this.unifiedOrder(req.getWayCode(), rq, payOrder);
    }

    private PayOrder getPayOrder(String token) {
        //解析token
        CashierTokenInfo tokenInfo = JSON.parseObject(PayUtils.aesDecode(token), CashierTokenInfo.class);
        String payOrderNo = tokenInfo.getPayOrderNo();

        PayOrder payOrder = payOrderService.getByPayOrderNo(payOrderNo);
        if (payOrder == null || !Objects.equals(payOrder.getStatus(), PayOrder.STATE_INIT)) {
            throw new BizException("订单不存在或状态不正确");
        }
        return payOrderService.getByPayOrderNo(payOrderNo);
    }


    private IChannelUserService getServiceByWayCode(String wayCode) {
        if (Cs.PAY_WAY_CODE.ALI_JSAPI.equals(wayCode)) {
            return AbstractChannelUserService.getService(IfCodeEnum.ALIPAY);
        } else if (Cs.PAY_WAY_CODE.WX_JSAPI.equals(wayCode)) {
            return AbstractChannelUserService.getService(IfCodeEnum.WXPAY);
        } else {
            throw new BizException("暂时不支持的 wayCode: {}", wayCode);
        }
    }
}
